JBoss Community Archive (Read Only)

GateIn Portal 3.8

Basic JSF Portlet Development

JSF stands for JavaServer Pages. The JSF version delivered by the built-in Portlet Bridge is 2.1.

Example Code

This section cites code from JSF2 Hello World Portlet from the Quickstarts Collection.

pom.xml

There is only one noticeable difference in pom.xml against what we have shown as a general case in the Starting a Portlet Project section: we only need to add JSF-specific dependencies:

pom.xml
068.     <dependencies>
069.         <!-- 
070.             The versions, scopes and types of these dependencies are managed in gatein-*-bom.
071.             You need to name only groupId and artifactId here.
072.             Name only those artifacts you refer to in your code.
073.             Look at gatein-*-bom POM file for the complete list of available artifacts.
074.         -->
075.         <dependency>
076.             <groupId>org.jboss.spec.javax.faces</groupId>
077.             <artifactId>jboss-jsf-api_2.1_spec</artifactId>
078.         </dependency>
079.         <dependency>
080.             <groupId>org.jboss.portletbridge</groupId>
081.             <artifactId>portletbridge-api</artifactId>
082.         </dependency>
083.     </dependencies>

JSF Template Files

In the following listing you can see the beginning of a typical JSF portlet template. It is taken from main.xhtml file located in src/main/webapp/pages directory.

Beginning of a JSF portlet template
17. <f:view xmlns="http://www.w3.org/1999/xhtml"  xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html">
18.     <!-- the f:view above prevents an erroneous <html> within <body> coming from portal. -->
19.     <!-- <h:head /> and <h:body> in the following are always needed otherwise JSF Facelets won't work -->
20.     <h:head />
21.     <h:body styleClass="jsf2HelloWorldPortlet">
22.         <h:outputStylesheet library="css" name="jsf2-hello-world-portlet.css" />
23.         <h2>JSF2 Hello World Portlet</h2>

Note that <f:view> as a root element of the portlet template above prevents an erroneous <html> within <body> coming from portal. Moreover, the <h:head> and <h:body> elements are always needed for JSF Facelets to work.

The following listing shows the use of several JSF elements, such as <h:outputLabel>, <h:inputText> and <h:commandButton> within <h:form>.

A form in a JSF portlet template
41.         <h:form id="jsf2HelloWorldPortlet">
42.             <h:outputLabel value="#{msgs.Name}" for="nameInput"/>
43.             <h:inputText id="nameInput" value="#{helloBean.name}">
44.                 <f:ajax render="output" event="keyup"/>
45.             </h:inputText>
46.             <br />
47.             
48.             <p>
49.                 <h:panelGroup id="output">
50.                     <strong>
51.                         <h:outputFormat value="#{msgs.Hello_0}" rendered="#{not empty helloBean.name}">
52.                             <f:param value="#{helloBean.name}" />
53.                         </h:outputFormat>
54.                     </strong>
55.                 </h:panelGroup>
56.             </p>
57.             
58.             <h:commandButton id="reset" value="#{msgs.Reset}" actionListener="#{helloBean.reset}">
59.                 <f:ajax render="@form" />
60.             </h:commandButton> - #{msgs.ResetComment}
61.             <br />
62.             <h:commandButton id="reload" value="#{msgs.Reload}" /> - #{msgs.ReloadComment}
63.             <br />
64.             
65.             <h:messages />
66.         </h:form>

The complete source code of the above template can be found in src/main/webapp/pages/main.xhtml of JSF2 Hello World Portlet project.

Java Beans

In the JSF template file shown above, we refer to helloBean. This bean is implemented in Java as follows:

26. /**
27.  * {@link HelloBean} is the JSF backing bean for the application, holding the input data to be re-displayed.
28.  */
29. @ManagedBean(name = "helloBean")
30. @SessionScoped
31. public class HelloBean implements Serializable {
32. 
33.     private static final long serialVersionUID = -6239437588285327644L;
34. 
35.     /**
36.      * Stores the name which will be used to greet the application user.
37.      */
38.     private String name;
39. 
40.     /**
41.      * Initializes {@link #name} with the value {@code "World"}.
42.      */
43.     @PostConstruct
44.     public void postContruct() {
45.         this.name = "World";
46.     }
47. 
48.     /**
49.      * Returns {@link #name}.
50.      * 
51.      * @return {@link #name}
52.      */
53.     public String getName() {
54.         return name;
55.     }
56. 
57.     /**
58.      * Set {@link #name}.
59.      * 
60.      * @param name
61.      */
62.     public void setName(String name) {
63.         this.name = name;
64.     }
65. 
66.     /**
67.      * Resets {@link #name} to the default value {@code "World"}.
68.      * 
69.      * @param ae ignored
70.      */
71.     public void reset(ActionEvent ae) {
72.         this.name = "World";
73.     }
74. 
75. }

The @ManagedBean and @SessionScoped annotations allow for omitting of equivalent declarations in the faces-config.xml file.

portlet.xml

portlet.xml is the place where we tie the JSF templates with the portlet.

portlet.xml
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd" version="2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd
   http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
    <portlet>
        <description>A simple JSF2 portlet.</description>
        <portlet-name>jsf2HelloWorldPortlet</portlet-name>
        <display-name>JSF2 Hello World Portlet</display-name>
        <portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.view</name>
            <value>/pages/main.xhtml</value>
        </init-param>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.edit</name>
            <value>/pages/edit.xhtml</value>
        </init-param>
        <init-param>
            <name>javax.portlet.faces.defaultViewId.help</name>
            <value>/pages/help.xhtml</value>
        </init-param>
        <init-param>
            <name>javax.portlet.faces.preserveActionParams</name>
            <value>true</value>
        </init-param>
        <expiration-cache>0</expiration-cache>
        <supports>
            <mime-type>text/html</mime-type>
            <portlet-mode>VIEW</portlet-mode>
            <portlet-mode>EDIT</portlet-mode>
            <portlet-mode>HELP</portlet-mode>
        </supports>
        <portlet-info>
            <title>JSF2 Hello World Portlet</title>
        </portlet-info>
        <container-runtime-option>
            <name>org.gatein.pc.remotable</name>
            <value>true</value>
        </container-runtime-option>
    </portlet>
</portlet-app>

   

Note that the javax.portlet.faces.defaultViewId.* init-params are used to bind the JSF templates with the respective portlet view modes. javax.portlet.faces.GenericFacesPortlet as a <portlet-class> will serve the purpose for most JSF portlets.

web.xml

JSF portlets require a few tweaks in the web.xml file:

web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
    <display-name>jsf2-hello-world-portlet</display-name>
    <context-param>
        <description>See https://docs.jboss.org/author/display/PBR/Render+Policy</description>
        <param-name>javax.portlet.faces.RENDER_POLICY</param-name>
        <param-value>ALWAYS_DELEGATE</param-value>
    </context-param>
    
    <!-- The following params are documented here: http://myfaces.apache.org/core21/myfaces-impl/webconfig.html -->
    <context-param>
        <param-name>javax.faces.FACELETS_VIEW_MAPPINGS</param-name>
        <param-value>*.xhtml</param-value>
    </context-param>
    <context-param>
        <param-name>facelets.DEVELOPMENT</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
</web-app>

Custom CSS

Portlet Bridge supports loading of CSS resources in the "JSF way". Just use the <h:outputStylesheet library="css" name="jsf2-hello-world-portlet.css" /> as we do in the main.xhtml file above. The jsf2-hello-world-portlet.css file needs to be placed in resources/css folder of the web application.

Note that relative paths like url('css/background/jsf-logo.png') do not work when used in CSS loaded via <h:outputStylesheet ...>. Rather a JSF Expression Language expression #{resource

['/css/background/jsf-logo.png']

} needs to be used. This expression is dynamically evaluated to a proper public URL. The path '/css/background/jsf-logo.png' used in the expression is relative to resources folder of the web application. See also Resource Serving.

jsf2-hello-world-portlet.css
17. div.jsf2HelloWorldPortlet {
18.     padding: 10px;
19.     /* In the following we use a JSF Expression Language expression rather then plain relative path. 
20.        Plain relative paths do not work in JSF portlets. The expression #{resource['...']} is 
21.        dynamically evaluated to a proper public URL. The path '/css/background/jsf-logo.png' 
22.        used in the expression is relative to  resources folder of this web application.
23.        See https://docs.jboss.org/author/display/PBR/Resource+Serving */
24.     background: url(#{resource['/css/background/jsf-logo.png']}) no-repeat;
25.     background-position-x: 753px;
26.     background-position-y: 10px;
27. }
28. div.jsf2HelloWorldPortlet p {
29.     width: 713px; 
30. }

Internationalization

Internationalization is supported via standard Java Resource bundles. In our example project the *.property files of org.jboss.as.quickstarts.jsf.messages resource bundle are stored under src/main/resources/org/jboss/as/quickstarts/jsf. The following settings in faces-config.xml are needed so that this bundle can be used in JSF templates.

faces-config.xml
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0">
    <application>
        <!-- Declare the internationalization resources -->
        <resource-bundle>
            <!-- The resource bundle property files are in src/main/resources/org/jboss/as/quickstarts/jsf -->
            <base-name>org.jboss.as.quickstarts.jsf.messages</base-name>
            <var>msgs</var>
        </resource-bundle>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>de</supported-locale>
        </locale-config>
    </application>
</faces-config>

Note that in the above faces-config.xml, we have made our bundle visible in JSF templates under the variable msgs. Its individual entries can then be accessed using the usual Expression Language dot notation: e.g. #{msgs.Name}.

Further Steps

After having done all the above, it is time to build and deploy the portlet, import it and add it to a page so that you can test its functionality.

See also

JBoss.org Content Archive (Read Only), exported from JBoss Community Documentation Editor at 2020-03-10 13:19:34 UTC, last content change 2013-05-30 14:11:01 UTC.